#include "encodevideo.h"

EncodeVideo::EncodeVideo()
{
    //1.注册组件
    av_register_all();
    this->isStop = false;
    this->isRun = false;

    this->count = 1000;
    this->current = 0;
    this->pktIndex = 0;
}

void EncodeVideo::initData()
{
    //查询最近一次的视频路径
    //设置视频保存的路径
    char **qres = nullptr;
    int col=0,row=0;
    int res = ConfigureModel::getInstance()->selectLastVideoPath(qres, row, col);
    if(res==0){
        this->videoPath=qres[1*col];
        qDebug() << "videoPath=" << videoPath;
    }
    this->pkt = av_packet_alloc();
    this->formatContext = avformat_alloc_context();
    qDebug() << "===============initEncode start===============";
    if(this->current==0)
    {
        //获取当前日期和时间
        QDateTime currentDateTime = QDateTime::currentDateTime();
        //获取当前时间
        QTime currentTime = currentDateTime.time();
        //获取当前日期
        QDate currentDate = currentDateTime.date();
        QString date = currentDateTime.toString("yyyy_MM_dd_hh_mm_ss");
        this->filename = QString("%1/" + date + ".h264").arg(this->videoPath);
    }
    qDebug() << "filename =" << filename;
    //2-1 创建文件，通过文件选择最佳格式
    this->format = av_guess_format(nullptr, filename.toStdString().c_str(), nullptr);
    if(format==nullptr){
        qDebug() << "format error";
    }
    else {
        qDebug() << "format success";
    }

    //2-2.设置格式
    this->formatContext->oformat = format;
    //3-1.新建图像（视频）流
    res = avio_open(&(this->formatContext->pb), filename.toStdString().c_str(), AVIO_FLAG_WRITE);
    if(res<0)
    {
        qDebug() << "avio_open error";
    }
    else {
        qDebug() << "avio_open success";
    }
    //3-2新建视频流
    AVStream * stream = avformat_new_stream(this->formatContext, nullptr);
    if(stream==nullptr){
        qDebug() << "new_stream error";
    }
    else {
        qDebug() << "new_stream success";
    }



//    //写入数据库
//    //获取当前日期和时间
    QDateTime currentDateTime = QDateTime::currentDateTime();
    //获取当前时间
    QTime currentTime = currentDateTime.time();
    //获取当前日期
    QDate currentDate = currentDateTime.date();
    QString date = currentDateTime.toString("yyyy_MM_dd_hh_mm_ss");
    datetime = currentDateTime.toString("yyyy-MM-dd hh:mm:ss");
//    QString filename = "../photo/" + date + ".jpg";
    QString filename = date + ".jpg";
    this->videoPath = QString("%1/" + filename).arg(this->videoPath);
    qDebug() << "encode： " << this->videoPath;
//    //获取登录的用户id
//        qres=nullptr;
//        col = 0,row=0;
//        res = UserModel::getInstance()->selectUserId(qres, row, col);
//    res = VideoModel::getInstance()->InsertVideo(this->filename, this->videoPath, datetime, atoi(qres[1]));
    //发送信号给解码，生成头帧
    emit makeHeadTalier(date);

    if(res==0){
        qDebug() << "插入视频成功";
    }
    else {
        qDebug() << "插入视频失败";
    }

    //3-3通过新建的流数据获取编码上下文对象
    this->codecContext = stream->codec;
    //3-4编码的基础信息
    this->codecContext->width = this->width;
    this->codecContext->height = this->height;
    this->codecContext->bit_rate = 400000;  //码率 单位是bps
    this->codecContext->time_base = {1,25}; //时间基   视频时间计算的基准
    this->codecContext->framerate = {25,1};     //帧率 播放画面切换的效率
    //3-5高级设置
    this->codecContext->gop_size = 10;  //I帧P帧B帧 10帧为一组
    this->codecContext->qmax = 51;      //清晰度
    this->codecContext->qmin = 10;      //清晰度
    this->codecContext->max_b_frames = 0;   //B帧最大压缩为0
    this->codecContext->pix_fmt = AV_PIX_FMT_YUV420P;
    this->codecContext->codec_type = AVMEDIA_TYPE_VIDEO;
    this->codecContext->codec_id = format->video_codec;        //编码id

    //4-1查找解码器
    AVCodec* codec = avcodec_find_encoder(this->codecContext->codec_id);
    //4-2打开解码器
    res = avcodec_open2(this->codecContext, codec, nullptr);
    if(res!=0)
    {
        qDebug() << "avcodec_open2 error";
    }
    else {
        qDebug() << "avcodec_open2 success";
    }
    //5.写入头帧数据到文件上下文对象中
    res = avformat_write_header(this->formatContext, nullptr);
    if(res<0)
    {
        qDebug() << "avformat_write_header error";
    }
    else {
        qDebug() << "avformat_write_header success";
    }
    qDebug() << "initEncode success";



}

void EncodeVideo::encodeFrame()
{
    //从队列中取一帧数据
    AVFrame *frame = this->queue.dequeue();
    int res = avcodec_send_frame(this->codecContext, frame);
    if(res<0){
        qDebug() << "avcodec_send_frame error";
    }
    else {
        qDebug() << "avcodec_send_frame success";
    }
    //进入编码阶段
    //一帧像素数据可能比较大， 一个AVpacket放不下，所有可能会有一个或两个帧读错
    while(res>=0)
    {
        frame->pts = this->pktIndex++;
        qDebug() << "this->pktIndex" << this->pktIndex;
        //7.将像素数据转成码流数据
        res = avcodec_receive_packet(this->codecContext, this->pkt);
        if(res==AVERROR(EAGAIN)|| res==AVERROR_EOF)
        {
            qDebug() << "avcodec_receive_packet error";
            break;
        }
        else {
            qDebug() << "avcodec_receive_packet success";
            this->current++;
        }
        //8.写一帧码流数据
        res = av_interleaved_write_frame(this->formatContext, this->pkt);
        if(res!=0)
        {
            qDebug() << "av_interleaved_write_frame error";
        }
        else {
            qDebug() << "av_interleaved_write_frame success";
        }
    }
    //释放资源
    av_packet_unref(this->pkt);
}


//写入尾帧数据
void EncodeVideo::writeTalier()
{
    //9.写入尾帧信息formatContext
    av_write_trailer(this->formatContext);
    //10.释放资源
    avio_close(this->formatContext->pb);
    avformat_free_context(this->formatContext);
    //获取登录的用户id
       char **qres=nullptr;
        int col = 0,row=0;
        int res = UserModel::getInstance()->selectUserId(qres, row, col);

    res = VideoModel::getInstance()->InsertVideo(this->filename, this->videoPath, datetime, this->current, atoi(qres[1]));

    QString name;
    if(atoi(qres[1])==1)
    {
        name = "100101";
    }
    else if(atoi(qres[1])==2) {
        name = "100102";
    }
    else {
        name = "100103";
    }
    qres=nullptr;
    col = 0,row=0;
    ConfigureModel::getInstance()->selectLastConfigure(qres, row, col);
    res = LogModel::getInstance()->InsertLog(this->datetime, qres[1], name, "录屏");

}

bool EncodeVideo::getIsStop() const
{
    return isStop;
}

void EncodeVideo::setIsStop(bool value)
{
    isStop = value;
}

bool EncodeVideo::getIsRun() const
{
    return isRun;
}

void EncodeVideo::setIsRun(bool value)
{
    isRun = value;
}

int EncodeVideo::getWidth() const
{
    return width;
}

void EncodeVideo::setWidth(int value)
{
    width = value;
}

int EncodeVideo::getHeight() const
{
    return height;
}

void EncodeVideo::setHeight(int value)
{
    height = value;
}


void EncodeVideo::run()
{
    while(this->isStop == false){
        while(this->isRun == true){
            if(!this->queue.isEmpty()){
//                this->msleep(40);
                qDebug() << "Encode this->queue->size()=" << this->queue.size();
                qDebug() << "this->current=" << this->current;
                if(this->current==0){
                    this->initData();
                    this->current++;
                }
                else if(this->current==this->count){
                    this->writeTalier();
                    this->current=0;
                }
                else if(this->current < this->count){
                    encodeFrame();
//                    this->current++;
                }
            }
        }
    }
}
